﻿using System;
using System.ComponentModel;
using System.IO;
using System.Text;
using System.Windows.Forms;
using BOIUK.WindowsFormsControls;

namespace BOF
{
    public partial class frmMain : Form
    {
        private PartialFileRead reader = new PartialFileRead();

        public frmMain()
        {
            InitForm();
        }
        public frmMain(string fileName)
        {
            InitForm();

            tstxtFileName.Text = fileName;
            tsbtnReload_Click(this, new EventArgs());
        }

        private void InitForm()
        {
            InitializeComponent();

            //attach reader events
            reader.ReadProgress += new ReadFileProgressChangedEventHandler(reader_ReadProgress);
            reader.FileRead += new FileReadEventHandler(reader_FileRead);

            //select read from start
            tsmnuStart_Click(this, new EventArgs());
            //and comma separated
            tsbtnCommaToTab_Click(this, new EventArgs());
            //and scrollbars
            tsbtnScrollbars_Click(this, new EventArgs());

            //for some reason RichTextBoxes don't have the usual DragDrop properties/events visible by default
            //so turn it on, and fire the form events.
            txtMain.AllowDrop = true;
            txtMain.DragDrop += Form1_DragDrop;
            txtMain.DragEnter += Form1_DragEnter;
        }


        void reader_FileRead(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("File Size: {0} kb, Modified Date: {1:d}", reader.FileInfo.Length / 1024, reader.FileInfo.LastWriteTime);
            sb.AppendFormat(", Read {0} Characters, {1} Lines", reader.ReadChars, reader.Lines);
            sb.AppendFormat(", Line Termination Bytes are: {0}", reader.LineTerminator);

            sslblStatus.Text = String.Format(sb.ToString());

            ssProgressBar.Value = 0;
            //resize progress bar
            Form1_Resize(this, new EventArgs());
        }

        void reader_ReadProgress(object sender, ReadProgressEventArgs e)
        {
            ssProgressBar.Value = e.Percentage;
        }

        private void tsbtnOpen_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog fd = new OpenFileDialog())
            {
                fd.CheckFileExists = true;
                if (fd.ShowDialog() == DialogResult.OK)
                {
                    tstxtFileName.Text = fd.FileName;
                    tsbtnReload_Click(this, new EventArgs());
                }
            }
        }

        private void tsbtnReload_Click(object sender, EventArgs e)
        {
            if (!String.IsNullOrEmpty(tstxtFileName.Text))
            {
                txtMain.Text = reader.ReadFile();
                this.errorProvider.SetError(tstxtFileName.TextBox, "");

                sslblHasFooter.Visible = reader.HasFooter;
                sslblHasHeader.Visible = reader.HasHeader;
            }
            else
            {
                this.errorProvider.SetError(tstxtFileName.TextBox, "Missing file name!");
            }

            if (!String.IsNullOrEmpty(txtMain.Text))
            {
                if (reader.HasHeader)
                    tsbtnHeaderLine.Checked = true;
                else
                    tsbtnHeaderLine.Checked = false;
            }
        }

        private void tsbtnSave_Click(object sender, EventArgs e)
        {
            if (String.IsNullOrEmpty(txtMain.Text))
                return;

            if (MessageBox.Show("This will overwrite " + tstxtFileName.Text + ", are you sure?"
                , Application.ProductName
                , MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                Cursor = Cursors.WaitCursor;

                using (StreamWriter s = new StreamWriter(tstxtFileName.Text))
                {
                    s.WriteLine(txtMain.Text);
                    s.Close();
                }

                Cursor = Cursors.Default;
            }
        }

        private void tsbtnScrollbars_Click(object sender, EventArgs e)
        {
            tsbtnScrollbars.Checked = !tsbtnScrollbars.Checked;
            switch (tsbtnScrollbars.Checked)
            {
                case true:
                    txtMain.ScrollBars = RichTextBoxScrollBars.ForcedBoth;
                    break;
                case false:
                    txtMain.ScrollBars = RichTextBoxScrollBars.None;
                    break;
                default:
                    break;
            }
        }

        private void tsbtnLineWrap_Click(object sender, EventArgs e)
        {
            tsbtnLineWrap.Checked = !tsbtnLineWrap.Checked;
            txtMain.WordWrap = tsbtnLineWrap.Checked;
        }

        private void tsbtnCommaToTab_Click(object sender, EventArgs e)
        {
            tsbtnCommaToTab.Checked = !tsbtnCommaToTab.Checked;
            reader.DoTabs = tsbtnCommaToTab.Checked;

            if (reader.DoTabs)
            {
                tsbtnCommaToTab.Text = "Tabs";
                tsbtnCommaToTab.Image = Properties.Resources.text_tab;
            }
            else
            {
                tsbtnCommaToTab.Text = "Commas";
                tsbtnCommaToTab.Image = Properties.Resources.text_comma;
            }
        }

        private void tsbtnHeaderLine_Click(object sender, EventArgs e)
        {
            tsbtnHeaderLine.Checked = !tsbtnHeaderLine.Checked;
        }

        private void tsmnuStart_Click(object sender, EventArgs e)
        {
            tsbtnReadDirection.Text = String.Format("Read From: {0}", "Start");
            tsbtnReadDirection.Image = tsmnuStart.Image;

            reader.ReadType = ReadType.Start;

            tstxtLines.Visible = true;
            tsbtnLinesPercentage.Visible = true;

            tstxtStart.Visible = false;
            tslblStart.Visible = false;
            tstxtEnd.Visible = false;
            tslblEnd.Visible = false;
        }

        private void tsmnuMiddle_Click(object sender, EventArgs e)
        {
            tsbtnReadDirection.Text = String.Format("Read From: {0}", "Middle");
            tsbtnReadDirection.Image = tsmnuMiddle.Image;

            reader.ReadType = ReadType.Middle;

            tstxtLines.Visible = false;
            tsbtnLinesPercentage.Visible = false;

            tstxtStart.Visible = true;
            tslblStart.Visible = true;
            tstxtEnd.Visible = true;
            tslblEnd.Visible = true;
        }

        private void tsmnuEnd_Click(object sender, EventArgs e)
        {
            tsbtnReadDirection.Text = String.Format("Read From: {0}", "End");
            tsbtnReadDirection.Image = tsmnuEnd.Image;

            reader.ReadType = ReadType.End;

            tstxtLines.Visible = true;
            tsbtnLinesPercentage.Visible = true;

            tstxtStart.Visible = false;
            tslblStart.Visible = false;
            tstxtEnd.Visible = false;
            tslblEnd.Visible = false;
        }

        private void tsbtnLinesPercentage_Click(object sender, EventArgs e)
        {
            switch (tsbtnLinesPercentage.Text)
            {
                case "Lines":
                    tsbtnLinesPercentage.Text = "%";
                    reader.LinesOrPercentage = LinesPercentage.Percentage;
                    break;
                case "%":
                    tsbtnLinesPercentage.Text = "Lines";
                    reader.LinesOrPercentage = LinesPercentage.Lines;
                    break;
                default:
                    break;
            }
        }

        private void tstxtFileName_TextChanged(object sender, EventArgs e)
        {
            reader.FileName = tstxtFileName.Text;
        }

        #region Control Validation

        private bool IsNumeric(string p, bool perc, out string errorMsg)
        {
            int number;
            if (int.TryParse(p, out number))
            {
                if (perc && (number < 0 || number > 100))
                {
                    errorMsg = "Enter a number between 0 and 100.";
                    return false;
                }
                else
                {
                    errorMsg = "";
                    return true;
                }
            }
            else
            {
                errorMsg = "Enter a numeric value.";
                return false;
            }
        }

        private void tstxtLines_Validating(object sender, CancelEventArgs e)
        {
            string errorMsg;

            bool perc = (reader.LinesOrPercentage == LinesPercentage.Percentage);

            if (!IsNumeric(tstxtLines.Text, perc, out errorMsg))
            {
                e.Cancel = true;
                tstxtLines.Select(0, tstxtLines.Text.Length);

                this.errorProvider.SetError(tstxtLines.TextBox, errorMsg);
            }
        }
        private void tstxtLines_Validated(object sender, EventArgs e)
        {
            errorProvider.SetError(tstxtLines.TextBox, "");
            reader.Lines = Convert.ToInt32(tstxtLines.Text);
        }

        private void tstxtStart_Validating(object sender, CancelEventArgs e)
        {
            string errorMsg;

            if (!IsNumeric(tstxtStart.Text, false, out errorMsg))
            {
                e.Cancel = true;
                tstxtStart.Select(0, tstxtStart.Text.Length);

                this.errorProvider.SetError(tstxtStart.TextBox, errorMsg);
            }
        }
        private void tstxtStart_Validated(object sender, EventArgs e)
        {
            errorProvider.SetError(tstxtStart.TextBox, "");
            reader.StartLine = Convert.ToInt32(tstxtStart.Text);
        }

        private void tstxtEnd_Validating(object sender, CancelEventArgs e)
        {
            string errorMsg;

            if (!IsNumeric(tstxtEnd.Text, false, out errorMsg))
            {
                e.Cancel = true;
                tstxtEnd.Select(0, tstxtEnd.Text.Length);

                this.errorProvider.SetError(tstxtEnd.TextBox, errorMsg);
            }
        }
        private void tstxtEnd_Validated(object sender, EventArgs e)
        {
            errorProvider.SetError(tstxtEnd.TextBox, "");
            reader.EndLine = Convert.ToInt32(tstxtEnd.Text);
        }

        #endregion

        private void Form1_Resize(object sender, EventArgs e)
        {
            //make the status bar look pretty
            int interalWidth = statusStrip.Width;
            int statusWidth = sslblStatus.Width;

            ssProgressBar.Width = interalWidth - statusWidth - 50;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.Text = Application.ProductName + " v" + Application.ProductVersion + ": " + Application.CompanyName;
        }

        private void tsbtnConvertTextToGrid_Click(object sender, EventArgs e)
        {
            if (gridMain.Visible)
            {
                tsbtnConvertTextToGrid.Checked = false;
                tsbtnCopyGrid.Enabled = false;
                gridMain.Visible = false;
                return;
            }

            //convert the text to a grid
            gridMain.Rows.Clear();
            gridMain.Columns.Clear();

            //first determine no of columns
            int maxcount = 0;
            foreach (string line in txtMain.Lines)
            {
                int linecount = line.Length - line.Replace(",", "").Length;
                if (linecount > maxcount)
                    maxcount = linecount;
            }

            //setup grid
            gridMain.ColumnCount = maxcount + 1;

            //add rows/header
            bool header = tsbtnHeaderLine.Checked;

            foreach (string line in txtMain.Lines)
            {
                if (!string.IsNullOrEmpty(line))
                {
                    //convert to array
                    string[] linearray = line.Split(new char[] { ',' }, StringSplitOptions.None);

                    if (header)
                    {
                        for (int i = 0; i < gridMain.Columns.Count; i++)
                            gridMain.Columns[i].Name = linearray[i].Trim();

                        header = false;
                    }
                    else
                        gridMain.Rows.Add(linearray);
                }
            }

            gridMain.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
            gridMain.AutoResizeRows(DataGridViewAutoSizeRowsMode.AllCells);

            tsbtnConvertTextToGrid.Checked = true;
            tsbtnCopyGrid.Enabled = true;
            gridMain.Visible = true;
        }

        private void tsbtnCopyGrid_Click(object sender, EventArgs e)
        {
            if (gridMain.GetCellCount(DataGridViewElementStates.Selected) > 0)
            {
                try
                {
                    Clipboard.SetDataObject(gridMain.GetClipboardContent());
                }
                catch (System.Runtime.InteropServices.ExternalException)
                {
                    MessageBox.Show("Clipboard could not be accessed, please try again!");
                }
            }
        }

        private void Form1_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop, true))
                e.Effect = DragDropEffects.All;
        }

        private void Form1_DragDrop(object sender, DragEventArgs e)
        {
            string[] files = (string[]) e.Data.GetData(DataFormats.FileDrop);
            //get the first filename
            tstxtFileName.Text = files[0];
            //open it
            tsbtnReload_Click(this, new EventArgs());
        }

        private void tsbtnAddFooter_Click(object sender, EventArgs e)
        {
            if (reader.HasFooter)
                txtMain.Text += reader.FooterLine;
            else
                MessageBox.Show("No Footer Line found!!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }

        private void tsbtnAddHeader_Click(object sender, EventArgs e)
        {
            if (reader.HasHeader)
                txtMain.Text = reader.HeaderLine + Environment.NewLine + txtMain.Text;
            else
                MessageBox.Show("No Header Line found!!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }

        private void txtMain_MouseDown(object sender, MouseEventArgs e)
        {
            UpdateCaretPosition();
        }

        private void txtMain_KeyPress(object sender, KeyPressEventArgs e)
        {
            UpdateCaretPosition();
        }
        private void txtMain_KeyDown(object sender, KeyEventArgs e)
        {
            UpdateCaretPosition();
        }
        private void txtMain_KeyUp(object sender, KeyEventArgs e)
        {
            UpdateCaretPosition();
        }


        private void UpdateCaretPosition()
        {
            CharPoint currPos = txtMain.GetCaretLCPosition;
            sslblPosition.Text = string.Format("(L:{0}, C:{1})", currPos.Line, currPos.Column);
        }

        private void tsbtnZoomOut_Click(object sender, EventArgs e)
        {
            if (txtMain.ZoomFactor - 0.25 >= 0.015f)
                txtMain.ZoomFactor -= 0.25f;
        }

        private void tsbtnZoomIn_Click(object sender, EventArgs e)
        {
            if (txtMain.ZoomFactor + 0.5 <= 5f)
                txtMain.ZoomFactor += 0.5f;
        }

        private void tsbtnZoomReset_Click(object sender, EventArgs e)
        {
            txtMain.ZoomFactor = 1.0f;
        }


    }
}
